package pl.enigmatic.relationship;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import pl.enigmatic.Action;


public class ActionGraph {

	private final Map<Action, List<Action>> actions = new HashMap<Action, List<Action>>();
	private final Map<Action, Object> blockers = new HashMap<Action, Object>();

	public boolean add(final Action action) {
		if (!actions.containsKey(action)) {
			actions.put(action, new Vector<Action>());
			blockers.put(action, action);
			return true;
		}
		return false;
	}

	public boolean connect(final Action from, final Action to) {
		add(from);
		final List<Action> list = actions.get(from);
		if (!list.contains(to)) {
			list.add(to);
			return true;
		}
		return false;
	}

	private GraphTS<Action> fillGraph(GraphTS<Action> ts, final Action from, final Set<Object> block) {
		ts.addVertex(from);
		block.add(blockers.get(from));
		for (final Action a : actions.get(from)) {
			if (!block.contains(blockers.get(a))) {
				ts.addEdge(from, a);
				ts = fillGraph(ts, a, block);
			}
		}
		return ts;
	}

	/**
	 * @param list actions to trigger
	 * @param block actions to block
	 * @return <code>true</code> if all actions finished with <code>true</code>
	 */
	public boolean fire(final List<Action> list, final Set<Object> block) {
		GraphTS<Action> ts = new GraphTS<Action>();
		for (final Action a : list) {
			ts = fillGraph(ts, a, block);
		}
		for (final Action a : ts.topo()) {
			if (a.performAction()) { return false; }
		}
		return true;
	}

	/**
	 * Sorts actions to fire topologically and fires them in that order
	 * @param list actions to trigger
	 */
	public boolean fire(final List<Action> list) {
		return fire(list, new HashSet<Object>());
	}

	public Object setBlocker(Action key, Object value) {
		return blockers.put(key, value);
	}

}
